/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.entities.transform;

import cn.easyplatform.entities.BaseEntity;
import cn.easyplatform.entities.EntityInfo;
import cn.easyplatform.entities.beans.LogicBean;
import cn.easyplatform.entities.beans.ResourceBean;
import cn.easyplatform.entities.beans.api.ApiBean;
import cn.easyplatform.entities.beans.batch.BatchBean;
import cn.easyplatform.entities.beans.bpm.BpmBean;
import cn.easyplatform.entities.beans.list.ListBean;
import cn.easyplatform.entities.beans.page.PageBean;
import cn.easyplatform.entities.beans.project.ProjectBean;
import cn.easyplatform.entities.beans.report.JasperReportBean;
import cn.easyplatform.entities.beans.report.JxlsReport;
import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.entities.beans.task.TaskBean;
import cn.easyplatform.entities.helper.CDataXMLStreamWriter;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.SubType;
import cn.easyplatform.utils.SerializationUtils;
import org.apache.commons.io.IOUtils;
import org.dom4j.io.OutputFormat;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class SimpleTransformer implements ITransformer {

    protected SimpleTransformer() {
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends BaseEntity> T transformFromXml(Class<T> clazz,
                                                     InputStream is) throws TransformException {
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller marshal = context.createUnmarshaller();
            T object = (T) marshal.unmarshal(is);
            return object;
        } catch (Exception ex) {
            throw new TransformException("transformFromXml", ex);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    @Override
    public <T extends BaseEntity> void transformToXml(T object, OutputStream os)
            throws TransformException {
        try {
            JAXBContext context = JAXBContext.newInstance(object.getClass());
            Marshaller marshal = context.createMarshaller();
            marshal.marshal(object, new CDataXMLStreamWriter(os,
                    new OutputFormat("  ", true, "UTF-8")));
        } catch (Exception ex) {
            throw new TransformException("transformToXml", ex);
        } finally {
            IOUtils.closeQuietly(os);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends BaseEntity> T transformFromXml(EntityInfo entity) {
        try {
            T bean = null;
            if (entity.getType().equals(EntityType.TABLE.getName()))
                bean = (T) transformFromXml(TableBean.class,
                        Lang.ins(entity.getContent()));
            else if (entity.getType().equals(EntityType.PAGE.getName())) {
                PageBean pb = transformFromXml(PageBean.class,
                        Lang.ins(entity.getContent()));
                if (!Strings.isBlank(entity.getExt0()))
                    pb.setAjax(entity.getExt0());
                if (!Strings.isBlank(entity.getExt1()))
                    pb.setMil(entity.getExt1());
                bean = (T) pb;
            } else if (entity.getType().equals(EntityType.DATALIST.getName())) {
                ListBean lb = transformFromXml(ListBean.class,
                        Lang.ins(entity.getContent()));
                if (!Strings.isBlank(entity.getExt0()))
                    lb.setPanel(entity.getExt0());
                bean = (T) lb;
            } else if (entity.getType().equals(EntityType.REPORT.getName())) {
                if (SubType.JASPER.getName().equals(entity.getSubType())) {
                    JasperReportBean rb = transformFromXml(
                            JasperReportBean.class,
                            Lang.ins(entity.getContent()));
                    rb.setReportModel(SerializationUtils.deserialize(rb
                            .getSerialize()));
                    rb.setSerialize(null);
                    rb.setContent(null);
                    bean = (T) rb;
                } else if (SubType.JXLS.getName().equals(entity.getSubType())) {
                    JxlsReport rb = transformFromXml(
                            JxlsReport.class,
                            Lang.ins(entity.getContent()));
                    bean = (T) rb;
                }
            } else if (entity.getType().equals(EntityType.TASK.getName()))
                bean = (T) transformFromXml(TaskBean.class,
                        Lang.ins(entity.getContent()));
            else if (entity.getType().equals(EntityType.BATCH.getName()))
                bean = (T) transformFromXml(BatchBean.class,
                        Lang.ins(entity.getContent()));
            else if (entity.getType().equals(EntityType.RESOURCE.getName())
                    || entity.getType().equals(EntityType.DATASOURCE.getName())) {
                if (SubType.CLASS.getName().equals(entity.getSubType()))
                    return (T) entity;
                bean = (T) transformFromXml(ResourceBean.class,
                        Lang.ins(entity.getContent()));
            } else if (entity.getType().equals(EntityType.LOGIC.getName())) {
                LogicBean lb = new LogicBean();
                lb.setContent(entity.getContent());
                bean = (T) lb;
            } else if (entity.getType().equals(EntityType.API.getName())) {
                bean = (T) transformFromXml(ApiBean.class,
                        Lang.ins(entity.getContent()));
            } else if (entity.getType().equals(EntityType.BPM.getName())) {
                BpmBean bb = new BpmBean();
                bb.setContent(entity.getContent());
                bean = (T) bb;
            } else if (entity.getType().equals(EntityType.PROJECT.getName()))
                bean = (T) transformFromXml(ProjectBean.class,
                        Lang.ins(entity.getContent()));
            else
                throw new TransformException("Not support type:"
                        + entity.getId() + "[" + entity.getType() + "]");
            bean.setId(entity.getId());
            bean.setType(entity.getType());
            bean.setSubType(entity.getSubType());
            bean.setName(entity.getName());
            bean.setDescription(entity.getDescription());
            return bean;
        } catch (TransformException ex) {
            throw new TransformException("transformFromXml->" + entity.getId()
                    + ":", ex.getCause());
        } catch (Exception ex) {
            throw new TransformException("Not support type:" + entity.getType() + "->" + entity.getSubType());
        }
    }
}
